import 'dart:convert';
import 'dart:typed_data';

import 'package:encrypt/encrypt.dart';

import 'package:pointycastle/export.dart';

// import 'package:pointycastle/key_generators/key_generator.dart';

String publicKeyPem = '''
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5Ai5FQpQwwzbqqB7guyEbzJ2A
MVI8PdNIdYCxuR0RPMznVT1kuRQjQwSQ6ipFtz0E9Ypg5Ye/I1qrz4JXla/YXDYG
uQYgBBO2GzuZLn119d+VL9PKjlhgdayV678XvIU/EQWFEJdDATyeaCjqaX+Rv8Co
SFXn4U509/5Sauqm5wIDAQAB
-----END PUBLIC KEY-----
''';

String privateKeyPem = '''
-----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQC5Ai5FQpQwwzbqqB7guyEbzJ2AMVI8PdNIdYCxuR0RPMznVT1k
uRQjQwSQ6ipFtz0E9Ypg5Ye/I1qrz4JXla/YXDYGuQYgBBO2GzuZLn119d+VL9PK
jlhgdayV678XvIU/EQWFEJdDATyeaCjqaX+Rv8CoSFXn4U509/5Sauqm5wIDAQAB
AoGBAJXTcEliu8Qps8WhVTBGG2/56uswBhsHLp4Vmp1S/nlBNed6Hnf9cpOD6KS7
HnTLCj2D5AbIm4BtTzaonDP14yr/xvPtr9PoY/Ect0yoCbLQ9yGDjv0u5X2q6Q68
Sdn/ZJuvQcLZ3Q2aGW7spQ11JY6JnIjcm3z/VhN3n8cOlwURAkEA9Ld338CXmAaw
i476GfS2r1S1dLKQX9U6zUXzj2Bctd34SD7QB0F89qrYOetgw7c2tEQZJ8s8pRSA
p0ldWBKEywJBAMGJ8VmnYilQdL0Zf9s61amvGv0VUcTYsXMAdLSFSbKgPRvs8m5j
Cmm7LvIXjqwz3MBmRb9KHRp3eAQsBCPrPtUCQQDGkWCppKLdbwAuHdP+37ykxD2A
9auEt4bBLfOV8YEI6ZYfOSif2pnFpZdSWBXqeW3gFCm9SoJpCRvjofomDtDFAkEA
wQTjCMgP9SZBlwqkYi+WQgnaP8gQaeK3bvtoaVV5P8XhzEUPL5plGzfMxTNLXmDG
67fUHcg7qFa4Amkno+8NFQJBANfSsAfeKdpFMyjU/HgOBy/reRi3cX7xt6sj0t4R
3ouA9HfDfwf+f1PRPWvRDkfhD+Oq+XCI89AELS1/hYF5COk=
-----END RSA PRIVATE KEY-----
''';

String base64UrlEncode(String input) {
  // 转换不安全的字符
  return input.replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', '');
}

String base64UrlDecode(String input) {
  // 恢复不安全的字符
  String paddedInput = input.replaceAll('-', '+').replaceAll('_', '/');
  // 补齐等号
  int padding = paddedInput.length % 4;
  if (padding > 0) {
    paddedInput += '=' * (4 - padding);
  }
  return paddedInput;
}

String fixBase64(String input) {
  // 移除空格和换行符
  String cleanInput = input.replaceAll(RegExp(r'[\s]+'), '');

  // 添加填充字符
  int padding = cleanInput.length % 4;
  if (padding > 0) {
    cleanInput += '=' * (4 - padding);
  }

  return cleanInput;
}

Uint8List concatenateBytes(List<Uint8List> byteList) {
  int totalLength = byteList.fold(0, (sum, bytes) => sum + bytes.length);
  Uint8List result = Uint8List(totalLength);
  int offset = 0;

  for (var bytes in byteList) {
    result.setRange(offset, offset + bytes.length, bytes);
    offset += bytes.length;
  }

  return result;
}

String decryptRSA(String encryptedData) {
  try {
    AsymmetricBlockCipher cipher = PKCS1Encoding(RSAEngine())
      ..init(false,
          PublicKeyParameter<RSAPublicKey>(parsePublicKey(publicKeyPem)));

    // var str = base64UrlDecode(encryptedData);
    //print('----- ${str}');
    final encryptedBytes = base64Decode(base64UrlDecode(encryptedData));
    print('++++');
    final inputLen = encryptedBytes.length;
    int offLen = 0;
    int i = 0;

    List<Uint8List> byteList = [];

    while (inputLen - offLen > 0) {
      final int chunkSize = (inputLen - offLen > 128) ? 128 : inputLen - offLen;
      final cache = cipher.process(
          Uint8List.sublistView(encryptedBytes, offLen, offLen + chunkSize));
      byteList.add(cache);
      i++;
      offLen = 128 * i;
    }

    final byteArray = concatenateBytes(byteList);
    return utf8.decode(byteArray);
  } catch (e) {
    print(e);
    // print('e ${}');
    return '';
  }
}

RSAPrivateKey parsePrivateKey(String pem) {
  final parser = RSAKeyParser();
  return parser.parse(pem) as RSAPrivateKey;
}

RSAPublicKey parsePublicKey(String pem) {
  final parser = RSAKeyParser();
  return parser.parse(pem) as RSAPublicKey;
}

String encryptRSA(String plaintext) {
  try {
    final cipher = PKCS1Encoding(RSAEngine())
      ..init(
          true, PublicKeyParameter<RSAPublicKey>(parsePublicKey(publicKeyPem)));

    final utf8Bytes = Uint8List.fromList(utf8.encode(plaintext));
    final inputLen = utf8Bytes.length;
    int offLen = 0;
    int i = 0;
    List<Uint8List> bops = [];

    while (inputLen - offLen > 0) {
      final chunkSize = (inputLen - offLen > 117) ? 117 : inputLen - offLen;
      final cache = cipher.process(
          Uint8List.sublistView(utf8Bytes, offLen, offLen + chunkSize));
      bops.add(cache);
      i++;
      offLen = 117 * i;
    }

    final encryptedData = concatenateBytes(bops);
    final base64Encoded = base64Encode(encryptedData);

    return base64Encoded;
  } catch (e) {
    print(e);
    return "";
  }
}
